#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include "Connection.hpp"

class HandlerEvents
{
public:
    HandlerEvents(func_t f)
        : _func(f)
    {
    }
    void HandlerRecv(Connection *conn)
    {
        errno = 0;
        LOG(DEBUG, "handler recv fd : %d\n", conn->GetSockfd());
        while (true)
        {
            char buff[1024];
            ssize_t n = ::recv(conn->GetSockfd(), buff, sizeof(buff) - 1, 0);
            if (n > 0)
            {
                buff[n] = 0;
                conn->AppendInbuff(buff);
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        _func(conn);
    }
    void HandlerSend(Connection *conn)
    {
        LOG(INFO, "handler send, fd : %d\n", conn->GetSockfd());
        errno = 0;
        while(true)
        {
            ssize_t n = ::send(conn->GetSockfd(), conn->OutBuffer().c_str(), conn->OutBuffer().size(), 0);
            if(n > 0)
            {
                conn->OutBuffer().erase(0, n);
                if(conn->OutBuffer().empty())
                    break;
            }
            else if(n == 0)
            {
                break;
            }
            else
            {
                if(errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                else if(errno == EINTR)
                {
                    continue;
                }
                else
                {
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        if(!conn->OutBuffer().empty())
        {
            conn->_R->EnableReadWrite(conn->GetSockfd(), true, true);
        }
        else
        {
            conn->_R->EnableReadWrite(conn->GetSockfd(), true, false);
        }
    }
    void HandlerExcept(Connection *conn)
    {
        errno = 0;
        LOG(INFO, "client quit, fd : %d\n", conn->GetSockfd());
        conn->_R->RemoveEvents(conn->GetSockfd());
    }

private:
    // 处理数据的接口，包括判断是否是一个完整的报文，反序列化请求，得到应答，序列化应答，将序列化之后的应答添加到outbuff中
    func_t _func;
};